<?php

namespace App\Services;

use App\Models\DoctorModel;
use App\Models\PatientModel;
use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
use Illuminate\Support\Facades\Log;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Arr;
use function Symfony\Component\Translation\t;
use App\Events\WechatTemplateMessage;
use Illuminate\Support\Facades\URL;

/**
 * @see https://wiki.swoole.com/#/start/start_ws_server
 */
class WebSocketService implements WebSocketHandlerInterface
{
    protected $uri;
    protected $wechatTemplateMessageIdForDoctor = 'wRzO6tdaZVIzb-qkAmvjtchCH1D306BSzlBFHZDgH5I';
    protected $wechatTemplateMessageIdForPatient = 'Cmj2-0YJPBuebWyiezNu03sqaDaCNn1zb9mqnbQRw8Q';

    //0-暂无 1-医助 2-营养师 3-健康管理师 4-心理咨询师 5-运动康复师 6-医生
    private function formatDoctorType($type)
    {
        switch ($type) {
            case 1:
                return '医助';
            case 2:
                return '营养师';
            case 3:
                return '健康管理师';
            case 4:
                return '心理咨询师';
            case 5:
                return '运动康复师';
            case 0:
            case 6:
                return '医生';
            default:
                return '';
        }
    }

    /**
     * 获取用户信息
     * @param $client
     * @param $userId
     * @return array
     */
    private function getUserInfo($client, $userId)
    {
        switch ($client) {
            case 'patient':
                $model = PatientModel::find($userId);
                if (!$model) return ['status' => false, 'data' => []];
                $data = [
                    'sign' => md5($client . '-' . $userId),
                    'client' => $client,
                    'userid' => $userId,
                    'username' => $model->patients_name,
                    'avatar' => $model->patients_img ?: "https://api.multiavatar.com/$model->data_id.png",
                    'role' => '',
                    'open_id' => $model->wx_oa_openid
                ];
                break;
            case 'doctor':
                $model = DoctorModel::find($userId);
                if (!$model) return ['status' => false, 'data' => []];
                $data = [
                    'sign' => md5($client . '-' . $userId),
                    'client' => $client,
                    'userid' => $userId,
                    'username' => $model->doctors_name,
                    'avatar' => $model->doctors_img ?: "https://api.multiavatar.com/$model->data_id.png",
                    'role' => $this->formatDoctorType($model->doctors_type),
                    'open_id' => $model->wx_oa_openid
                ];
                break;
            default:
                return ['status' => false, 'data' => []];
        }
        return ['status' => true, 'data' => $data];
    }

    /**
     * 记录聊天内容
     */
    private function writeChatRecords($data = [], $roomId = 0)
    {
        if (empty($roomId)) return ['status' => false, 'msg' => '会话不存在'];
        if (empty($data)) return ['status' => false, 'msg' => '没有聊天数据'];
        $redisChatRecordTable = 'chatroom:chat-records';
        // 先获取之前的内容拼装后存入redis
        $historyData = Redis::hget($redisChatRecordTable, 'chatroom:' . $roomId);
        $historyData = $historyData ? json_decode($historyData, true) : [];
        $historyData[] = $data;
        $status = Redis::hset($redisChatRecordTable, 'chatroom:' . $roomId, json_encode($historyData));
        // \Log::info('writeChatRecords：'.$roomId.'：', $status);
        return ['status' => true];
    }

    /**
     * 处理微信模板消息消息内容
     * @param $data
     * @return string|void
     */
    private function formatContent($data)
    {
        if (isset($data->message_type)) {
            switch ($data->message_type) {
                case 'text':
                    return nl2br(htmlspecialchars($data->content));
                case 'voice':
                    return '[语音消息]';
                case 'image':
                    return '[图片]';
            }
        } else {
            return nl2br(htmlspecialchars($data->content));
        }

    }

    // 声明没有参数的构造函数
    public function __construct()
    {
        $url = url()->current();
        $this->uri = isset(explode('/ws', $url)[0]) ? explode('/ws', $url)[0] : $url;
        echo $this->uri;
    }
    // public function onHandShake(Request $request, Response $response)
    // {
    // 自定义握手：https://wiki.swoole.com/#/websocket_server?id=onhandshake
    // 成功握手之后会自动触发onOpen事件
    // }
    public function onOpen(Server $server, Request $request)
    {
        // 在触发onOpen事件之前，建立WebSocket的HTTP请求已经经过了Laravel的路由，
        // 所以Laravel的Request、Auth等信息是可读的，Session是可读写的，但仅限在onOpen事件中。
        // \Log::info('New WebSocket connection', [$request->fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);
        // 此处抛出的异常会被上层捕获并记录到Swoole日志，开发者需要手动try/catch
        $server->push($request->fd, '{}');
    }

    public function onMessage(Server $server, Frame $frame)
    {
        $data = json_decode($frame->data);
        $redisUserTable = 'chatroom:' . $data->roomId;
        $sign = md5($data->client . '-' . $data->userId);
        switch ($data->type) {
            case 'pong':
                return;
            case 'login':
                if (!isset($data->roomId)) {
                    $server->push($frame->fd, json_encode(['type' => 'error', 'msg' => '会话不存在']));
                }
                // 创建并加入群聊
                $userInfo = $this->getUserInfo($data->client, $data->userId);
                if ($userInfo['status'] === false) {
                    $server->push($frame->fd, json_encode(['type' => 'error', 'msg' => '未知用户']));
                }
                // 加入群聊
                Redis::hset($redisUserTable, $sign, json_encode($userInfo['data']));

                $message = array(
                    'fd' => $frame->fd,
                    'type' => $data->type,
                    'room_id' => $data->roomId,
                    'time' => date('Y-m-d H:i:s'),
                );
                $server->push($frame->fd, json_encode($message));
                return;
            case 'say':
                $currentTime = date('Y-m-d H:i:s');
                if (!isset($data->roomId)) {
                    $server->push($frame->fd, json_encode(['type' => 'error', 'msg' => '会话不存在']));
                }

                $redisUser = Redis::hget($redisUserTable, $sign);
                $redisUser = json_decode($redisUser, true);

                $message = [
                    'fd' => $frame->fd,
                    'type' => $data->type,
                    'userid' => $redisUser['userid'],
                    'username' => $redisUser['username'],
                    'avatar' => $redisUser['avatar'],
                    'room_id' => $data->roomId,
                    'content' => nl2br(htmlspecialchars($data->content)),
                    'time' => $currentTime,
                    'message_type' => $data->message_type,
                    'duration' => isset($data->duration) ? round($data->duration / 1000) : ''
                ];

                // 记录聊天内容
                $this->writeChatRecords($message, $data->roomId);

                $msgData = [];
                // 查询当前聊天室的所有用户
                $redisRoomUsers = Redis::hGetAll($redisUserTable);
                if (!empty($redisRoomUsers)) {
                    $content = $this->formatContent($data);
                    // 如果当前发言人为医生，则查询该聊天室内的所有患者
                    if ($data->client == 'doctor') {
                        foreach ($redisRoomUsers as $key => $user) {
                            $userData = json_decode($user, true);
                            if (isset($userData['client']) && $userData['client'] == 'patient') {
                                $query = http_build_query(['roomid' => $data->roomId, 'client' => $userData['client'], 'userid' => $userData['userid']]);
                                $msgData[] = [
                                    'touser' => $userData['open_id'],
                                    'template_id' => $this->wechatTemplateMessageIdForPatient,
                                    'url' => $this->uri . '/chatroom?' . $query,
                                    'data' => [
                                        'first' => '您好，有医生回复了您的消息',
                                        'keyword1' => $user['role'] ?? '' . $redisUser['username'],
                                        'keyword2' => $currentTime,
                                        'keyword3' => $content,
                                        'remark' => '点击查看详情',
                                    ]

                                ];
                            }
                        }
                    } else {
                        // 如果当前发言人为患者，则查询该聊天室内的所有医生
                        foreach ($redisRoomUsers as $key => $user) {
                            $userData = json_decode($user, true);

                            if (isset($userData['client']) && $userData['client'] == 'doctor') {
                                $query = http_build_query(['roomid' => $data->roomId, 'client' => $userData['client'], 'userid' => $userData['userid']]);
                                $msgData[] = [
                                    'touser' => $userData['open_id'],
                                    'template_id' => $this->wechatTemplateMessageIdForDoctor,
                                    'url' => $this->uri . '/chatroom?' . $query,
                                    'data' => [
                                        'first' => '您好，有患者发来新的消息',
                                        'keyword1' => $redisUser['username'],
                                        'keyword2' => $content,
                                        'keyword3' => $currentTime,
                                        'remark' => '点击查看详情',
                                    ]

                                ];
                            }
                        }
                    }
                }

                event(new WechatTemplateMessage($msgData));

                foreach ($server->connections as $fd) {
                    $connectionInfo = $server->connection_info($fd);
                    if ($connectionInfo['websocket_status'] == 3) {
                        $server->push($fd, json_encode($message)); //长度最大不得超过2M
                    }
                }
                return;
        }
    }

    public function onClose(Server $server, $fd, $reactorId)
    {
        // 此处抛出的异常会被上层捕获并记录到Swoole日志，开发者需要手动try/catch
    }
}
